package web.suzy.oj.manager.admin.user;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import web.suzy.oj.common.exception.StatusFailException;
import web.suzy.oj.dao.user.SysUserRoleEntityService;
import web.suzy.oj.dao.user.UserInfoEntityService;
import web.suzy.oj.dao.user.UserRecordEntityService;
import web.suzy.oj.manager.msg.AdminNoticeManager;
import web.suzy.oj.pojo.dto.AdminEditUserDTO;
import web.suzy.oj.pojo.entity.user.SysUserRole;
import web.suzy.oj.pojo.entity.user.UserInfo;
import web.suzy.oj.pojo.entity.user.UserRecord;
import web.suzy.oj.pojo.vo.SysUserRoleVO;
import web.suzy.oj.shiro.AccountProfile;
import web.suzy.oj.utils.Constants;
import web.suzy.oj.utils.RedisUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * YangSuzy 软件工作室
 * 类名: AdminUserManager
 * 描述: ---- 待定 -----
 * 功能: ---- 待定 -----
 *
 * @author YangSuzy
 * Date: 2022/11/17 19:02
 */

@Component
@Slf4j(topic = "suzyoj")
public class AdminUserManager {
    @Autowired
    private SysUserRoleEntityService userRoleEntityService;

    @Autowired
    private UserInfoEntityService userInfoEntityService;

    @Autowired
    private AdminNoticeManager adminNoticeManager;

    @Autowired
    private UserRecordEntityService userRecordEntityService;

    @Autowired
    private RedisUtils redisUtils;


    /**
     * 方法名: getUserList
     * 描述: 根据关键字分页查询用户列表
     *
     * @param limit       每页显示数量
     * @param currentPage 当前页
     * @param onlyAdmin   是否只查管理员
     * @param keyword     关键字
     * @return com.baomidou.mybatisplus.core.metadata.IPage<web.suzy.oj.pojo.vo.SysUserRoleVO>
     * @date 2022/11/17 19:04
     * @auther YangSuzy
     **/
    public IPage<SysUserRoleVO> getUserList(Integer limit, Integer currentPage, Boolean onlyAdmin, String keyword) {
        //未给页码信息时设置默认当前页为第一页
        if (currentPage == null || currentPage < 1) {
            currentPage = 1;
        }
        //未给每页显示数量时设置默认为10
        if (limit == null || limit < 1) {
            limit = 10;
        }
        //清除关键字的空格
        if (keyword != null) {
            keyword = keyword.trim();
        }
        return userRoleEntityService.getUserList(limit, currentPage, keyword, onlyAdmin);
    }

    /**
     * 方法名: deleteUser
     * 描述: 批量删除用户
     *
     * @param deleteUserIdList 待删除用户列表
     * @return void
     * @date 2022/11/17 21:38
     * @auther YangSuzy
     **/
    public void deleteUser(List<String> deleteUserIdList) throws StatusFailException {
        boolean isOk = userInfoEntityService.removeByIds(deleteUserIdList);
        if (!isOk) {
            throw new StatusFailException("删除失败！");
        }
        AccountProfile userRolesVo = (AccountProfile) SecurityUtils.getSubject().getPrincipal();
        log.info("[{}],[{}],uidList:[{}],operatorUid:[{}],operatorUsername:[{}]",
                "Admin_User", "Delete", deleteUserIdList, userRolesVo.getUid(), userRolesVo.getUsername());
    }

    /**
     * 方法名: editUser
     * 描述: 管理员修改用户信息
     *
     * @param adminEditUserDto 管理员修改用户数据传输对象
     * @return void
     * @date 2022/11/27 17:19
     * @auther YangSuzy
     **/
    public void editUser(AdminEditUserDTO adminEditUserDto) throws StatusFailException {
        //获取修改后的用户信息
        String username = adminEditUserDto.getUsername();
        String uid = adminEditUserDto.getUid();
        String realname = adminEditUserDto.getRealname();
        String email = adminEditUserDto.getEmail();
        String password = adminEditUserDto.getPassword();
        int type = adminEditUserDto.getType();
        int status = adminEditUserDto.getStatus();
        //是否设置新的密码
        boolean setNewPwd = adminEditUserDto.getSetNewPwd();

        //用户信息校验
        if (!StringUtils.isEmpty(realname) && realname.length() > 50) {
            throw new StatusFailException("真实姓名的长度不能超过50位");
        }
        if (!StringUtils.isEmpty(password) && (password.length() < 6 || password.length() > 20)) {
            throw new StatusFailException("密码长度建议为6~20位！");
        }
        if (username.length() > 20) {
            throw new StatusFailException("用户名长度建议不能超过20位!");
        }

        //更新用户信息
        UpdateWrapper<UserInfo> userInfoUpdateWrapper = new UpdateWrapper<>();
        userInfoUpdateWrapper.eq("uuid", uid)
                .set("username", username)
                .set("realname", realname)
                .set("email", email)
                //需要重置密码再将密码MD5加密保存
                .set(setNewPwd, "password", SecureUtil.md5(password))
                .set("status", status);
        boolean updateUserInfo = userInfoEntityService.update(userInfoUpdateWrapper);
        //查询修改用户的角色
        QueryWrapper<SysUserRole> userRoleQueryWrapper = new QueryWrapper<>();
        userRoleQueryWrapper.eq("uid", uid);
        SysUserRole userRole = userRoleEntityService.getOne(userRoleQueryWrapper, false);
        boolean changeUserRole = false;
        //获取用户的旧角色的ID
        int oldType = userRole.getRoleId().intValue();
        if (userRole.getRoleId().intValue() != type) {
            //新设置的角色和原来角色不相同时重设角色
            userRole.setRoleId((long) type);
            changeUserRole = userRoleEntityService.updateById(userRole);
            if (type == 1000 || oldType == 1000) {
                //新增或者去除超级管理员权限需要删除缓存
                String cacheKey = Constants.Account.SUPER_ADMIN_UID_LIST_CACHE.getCode();
                redisUtils.del(cacheKey);
            }
        }
        //更新用户信息和重设密码后需要重新登录
        if (updateUserInfo && setNewPwd) {
            userRoleEntityService.deleteCache(uid, true);
        } else if (changeUserRole) {
            //只修改了用户角色只需重新授权
            userRoleEntityService.deleteCache(uid, false);
        }
        //修改用户角色后需要发送权限变更通知
        if (changeUserRole) {
            //获取当前登录的用户
            AccountProfile userRolesVo = (AccountProfile) SecurityUtils.getSubject().getPrincipal();
            String title = "权限变更通知(Authority Change Notice)";
            String content = userRoleEntityService.getAuthChangeContent(oldType, type);
            adminNoticeManager.addSingleNoticeToUser(userRolesVo.getUid(), uid, title, content, "Sys");
        }
    }


    /**
     * 方法名: generateUser
     * 描述: 快速生成用户 用户名：前缀 + 数字 + 后缀
     *
     * @param params 用户数据参数
     * @return java.util.Map<java.lang.Object, java.lang.Object>
     * @date 2022/11/27 16:42
     * @auther YangSuzy
     **/
    @Transactional(rollbackFor = Exception.class)
    public Map<Object, Object> generateUser(Map<String, Object> params) throws StatusFailException {
        //用户名前缀，未输入默认为空
        String prefix = (String) params.getOrDefault("prefix", "");
        //用户名后缀，未输入默认为空
        String suffix = (String) params.getOrDefault("suffix", "");
        //用户名拼接 - 开始数字，默认为1
        int numberFrom = (int) params.getOrDefault("number_from", 1);
        //用户名拼接 - 结束数字，默认为10
        int numberTo = (int) params.getOrDefault("number_to", 10);
        //密码长度：6位
        int passwordLength = (int) params.getOrDefault("password_length", 6);

        //存储用户信息、用户角色、用户做题记录的列表
        List<UserInfo> userInfoList = new LinkedList<>();
        List<SysUserRole> userRoleList = new LinkedList<>();
        List<UserRecord> userRecordList = new LinkedList<>();

        //存储账号密码放入redis中，等待导出excel
        HashMap<String, Object> userInfo = new HashMap<>();
        for (int num = numberFrom; num <= numberTo; num++) {
            //生成用户uid
            String uuid = IdUtil.simpleUUID();
            //随机生成6位密码
            String password = RandomUtil.randomString(passwordLength);
            //拼接用户名：前缀+数字+后缀
            String username = prefix + num + suffix;
            //存储需要批量生成的用户
            userInfoList.add(new UserInfo()
                    .setUuid(uuid)
                    .setUsername(username)
                    .setPassword(SecureUtil.md5(password)));
            //缓存中存储生成的用户名和未加密的密码
            userInfo.put(username, password);
            //设置用户角色为默认用户
            userRoleList.add(new SysUserRole()
                    .setRoleId(1002L)
                    .setUid(uuid));
            //初始化用户的做题记录
            userRecordList.add(new UserRecord().setUid(uuid));
        }
        //批量保存用户信息、用户角色、用户做题记录
        boolean result1 = userInfoEntityService.saveBatch(userInfoList);
        boolean result2 = userRoleEntityService.saveBatch(userRoleList);
        boolean result3 = userRecordEntityService.saveBatch(userRecordList);
        if (result1 && result2 && result3) {
            String key = IdUtil.simpleUUID();
            //缓存保留30分钟生成的用户名和密码
            redisUtils.hmset(key, userInfo, 1800);
            //异步同步系统通知
            List<String> uidList = userInfoList.stream().map(UserInfo::getUuid).collect(Collectors.toList());
            adminNoticeManager.syncNoticeToNewRegisterBatchUser(uidList);
            //返回缓存的key，给前端查询用
            return MapUtil.builder().put("key", key).map();
        }
        throw new StatusFailException("生成指定用户失败！注意查看组合生成的用户名是否已有存在的！");
    }

    /**
     * 方法名: insertBatchUser
     * 描述: 通过CSV文件批量导入用户
     *
     * @param users 用户信息列表
     * @return void
     * @date 2022/11/27 18:39
     * @auther YangSuzy
     **/
    public void insertBatchUser(List<List<String>> users) throws StatusFailException {
        //插入成功的用户集
        List<String> successUidList = new LinkedList<>();
        if (users != null) {
            //插入失败的用户集
            HashSet<String> failedUserNameSet = new HashSet<>();
            for (List<String> user : users) {
                try {
                    //添加新用户
                    String uuid = addNewUser(user);
                    if (uuid != null) {
                        successUidList.add(uuid);
                    } else {
                        //添加失败时保存添加失败的用户名
                        failedUserNameSet.add(user.get(0));
                    }
                } catch (Exception e) {
                    //抛出异常时保存添加失败的用户名
                    failedUserNameSet.add(user.get(0));
                }
            }
            // 异步同步系统通知
            if (successUidList.size() > 0) {
                //向管理员发送批量添加用户成功通知
                adminNoticeManager.syncNoticeToNewRegisterBatchUser(successUidList);
            }
            if (failedUserNameSet.size() > 0) {
                //有添加失败的数据都需要抛出异常
                int failedCount = failedUserNameSet.size();
                int successCount = users.size() - failedCount;
                String errMsg = "[导入结果] 成功数：" + successCount + ",  失败数：" + failedCount +
                        ",  失败的用户名：" + failedUserNameSet;
                throw new StatusFailException(errMsg);
            }
        } else {
            throw new StatusFailException("插入的用户数据不能为空！");
        }
    }

    /**
     * 方法名: addNewUser
     * 描述: 添加新用户
     *
     * @param user 用户信息：用户名，密码，年级，专业，班级，学号，邮箱，真实姓名，性别，昵称
     * @return java.lang.String
     * @date 2022/11/27 18:43
     * @auther YangSuzy
     **/
    @Transactional(rollbackFor = Exception.class)
    public String addNewUser(List<String> user) throws StatusFailException {
        //生成用户uid
        String uuid = IdUtil.simpleUUID();
        //添加用户信息
        UserInfo userInfo = new UserInfo()
                //用户uid
                .setUuid(uuid)
                //用户名
                .setUsername(user.get(0))
                //MD5加密密码
                .setPassword(SecureUtil.md5(user.get(1)));
        //设置用户年级
        if (user.size() >= 3) {
            String grade = user.get(2);
            if (!StringUtils.isEmpty(grade)) {
                userInfo.setGrade(grade);
            }
        }
        //设置用户专业
        if (user.size() >= 4) {
            String course = user.get(3);
            if (!StringUtils.isEmpty(course)) {
                userInfo.setCourse(course);
            }
        }
        //设置用户班级
        if (user.size() >= 5) {
            String classes = user.get(4);
            if (!StringUtils.isEmpty(classes)) {
                userInfo.setClasses(classes);
            }
        }
        //设置用户学号
        if (user.size() >= 6) {
            String number = user.get(5);
            if (!StringUtils.isEmpty(number)) {
                userInfo.setNumber(number);
            }
        }
        //设置用户邮箱
        if (user.size() >= 7) {
            String email = user.get(6);
            if (!StringUtils.isEmpty(email)) {
                userInfo.setEmail(email);
            }
        }
        //设置用户真实姓名
        if (user.size() >= 8) {
            String realname = user.get(7);
            if (!StringUtils.isEmpty(realname)) {
                userInfo.setRealname(realname);
            }
        }
        //设置用户性别
        if (user.size() >= 9) {
            String gender = user.get(8);
            if ("male".equals(gender.toLowerCase()) || "0".equals(gender)) {
                userInfo.setGender("male");
            } else if ("female".equals(gender.toLowerCase()) || "1".equals(gender)) {
                userInfo.setGender("female");
            }
        }
        //设置用户昵称
        if (user.size() >= 10) {
            String nickname = user.get(9);
            if (!StringUtils.isEmpty(nickname)) {
                userInfo.setNickname(nickname);
            }
        }

        //保存用户信息
        boolean result1 = userInfoEntityService.save(userInfo);
        //设置用户角色为默认用户
        SysUserRole userRole = new SysUserRole()
                .setRoleId(1002L)
                .setUid(uuid);
        boolean result2 = userRoleEntityService.save(userRole);
        //初始化用户做题记录
        UserRecord userRecord = new UserRecord().setUid(uuid);
        boolean result3 = userRecordEntityService.save(userRecord);
        if (!result1 || !result2 || !result3) {
            throw new StatusFailException("生成用户失败");
        }
        //返回用户uuid
        return uuid;
    }
}
